#include "event/znx_worker_proc.h"
#include "event/znx_single_flight.h"

znx_single_flight_t sf;
znx_single_flight_t sf1;

typedef struct {
    int                     id;
    const char              *sf_key;
    int                     step;
    znx_event_t             event;
    znx_dispatch_event_t    dispatch_event;
    znx_single_flight_t     *sfp;
} znx_sf_test_t;


static int
znx_dispatch_event_cmp(znx_dispatch_event_t *a,
    znx_dispatch_event_t *b)
{
    znx_sf_test_t *test_a = a->data;
    znx_sf_test_t *test_b = b->data;

    return strcmp(test_a->sf_key, test_b->sf_key);
}


static void
sf_test_done(znx_dispatch_event_t *dispatch_event)
{
    znx_event_loop_async_task_decr();
    znx_sf_test_t *test = dispatch_event->data;
    const char *result = dispatch_event->save_data_2;
    ZNX_DEF_LOG_DEBUG("task: %s-%d, result: %s, thread: %p", test->sf_key,
        test->id, result, current_thread_base);
    znx_thread_free(test);
}


static void
sf_test_timer_handle(znx_event_t *event)
{
    znx_sf_test_t *test = event->data;

    ZNX_DEF_LOG_DEBUG("task: %s-%d, step: %d, thread: %p", test->sf_key,
        test->id, test->step, current_thread_base);

    if (test->step < 5) {
        znx_event_loop_add_timer(&test->event, 100);
        test->step++;
        return;
    }

    znx_single_flight_notify(test->sfp, &test->dispatch_event, "exec success");
}


static void
sf_test_do(znx_dispatch_event_t *dispatch_event)
{
    znx_sf_test_t *test = dispatch_event->data;
    test->event.handler = sf_test_timer_handle;
    test->step = 0;
    znx_event_loop_add_timer(&test->event, 100);
}


static void
znx_test_sf_handler(znx_dispatch_event_t *dispatch_event)
{
    int id = (int)(intptr_t)dispatch_event->data;
    const char *sf_key = dispatch_event->save_data_1;
    znx_single_flight_t *sfp = dispatch_event->save_data_2;

    free(dispatch_event);

    znx_sf_test_t *test = znx_thread_calloc(sizeof(znx_sf_test_t));
    test->id = id;
    test->sf_key = sf_key;
    test->event.data = test;
    test->dispatch_event.data = test;
    test->dispatch_event.handler = sf_test_done;
    test->sfp = sfp;

    znx_single_flight_do(sfp, &test->dispatch_event, sf_test_do);
    znx_event_loop_async_task_incr();
}


static void
test_sf(int i, const char *task_name,
    znx_single_flight_t *sfp)
{
    znx_dispatch_event_t *dispatch_event =
        malloc(sizeof(znx_dispatch_event_t));
    dispatch_event->handler = znx_test_sf_handler;
    dispatch_event->data = (void *)(intptr_t)i;
    dispatch_event->save_data_1 = (void *)task_name;
    dispatch_event->save_data_2 = sfp;
    znx_worker_processor_post_event(dispatch_event);
}


void
sf1_free(znx_dispatch_event_t *dispatch_event)
{
    znx_sf_test_t *test = dispatch_event->data;
    const char *result = dispatch_event->save_data_2;
    ZNX_DEF_LOG_DEBUG("fake master, task: %s-%d, result: %s, thread: %p", test->sf_key,
        test->id, result, current_thread_base);
    znx_thread_free(test);
}


znx_dispatch_event_t *
znx_sf1_master_create(znx_dispatch_event_t *old_dispatch_event)
{
    znx_sf_test_t *old_test = old_dispatch_event->data;
    znx_sf_test_t *test =
        znx_thread_calloc(sizeof(znx_sf_test_t));
    test->id = old_test->id;
    test->sf_key = old_test->sf_key;
    test->event.data = test;
    test->dispatch_event.data = test;
    test->dispatch_event.handler = sf1_free;
    test->sfp = old_test->sfp;

    ZNX_DEF_LOG_DEBUG("create fake master dispatch event");

    return &test->dispatch_event;
}

int main()
{
    znx_worker_processor_init();

    znx_def_log_init(0, LOG_LEVEL_DEBUG, NULL, LOG_ROLLING_DAY);
    znx_single_flight_init(&sf, znx_dispatch_event_cmp, NULL, NULL);
    znx_single_flight_init(&sf1, znx_dispatch_event_cmp,
        znx_sf1_master_create, NULL);

    znx_worker_processor_start(1, 1, 1);

    for (int i = 0; i < 10; i++) {
        test_sf(i, "sf_task_0", &sf);
        test_sf(i, "sf_task_1", &sf);
        test_sf(i, "sf_task_2", &sf);
        test_sf(i, "sf_task_3", &sf);
        test_sf(i, "sf_task_4", &sf);
        test_sf(i, "sf_task_5", &sf);
        test_sf(i, "sf_task_6", &sf);
        test_sf(i, "sf_task_7", &sf);
        test_sf(i, "sf_task_8", &sf);
        test_sf(i, "sf_task_9", &sf);
    }

    for (int i = 0; i < 1; i++) {
        test_sf(i, "sf1_task_0", &sf1);
        test_sf(i, "sf1_task_1", &sf1);
        test_sf(i, "sf1_task_2", &sf1);
        test_sf(i, "sf1_task_3", &sf1);
        test_sf(i, "sf1_task_4", &sf1);
        test_sf(i, "sf1_task_5", &sf1);
        test_sf(i, "sf1_task_6", &sf1);
        test_sf(i, "sf1_task_7", &sf1);
        test_sf(i, "sf1_task_8", &sf1);
        test_sf(i, "sf1_task_9", &sf1);
    }

    proc_exit = ZNX_TRUE;

    while (!znx_worker_processor_all_task_done()) {
        usleep(10000);
    }

    znx_worker_processor_stop();

    return 0;
}